package own.stu.jobgib.playown.basic.generic;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * GenericDeclaration 有三个直接子类 Class,Construtor,Method,
 * 也就是说只能在这几种对象上进行范型变量的声明（定义）。
 * GenericDeclaration的接口方法getTypeParameters用来逐个获取该GenericDeclaration的范型变量声明。
 */
public class GenericDecalarationTest {


    class Person {
        List<Integer> integerList;
        Map<String, Integer> belongs;
    }

    //1.在类（Class）上声明（定义）类型变量
    class A<T> {
        T a;
    }//之后这里可用任意类型替换T，例如

    A<String> as = new A<String>();
    //是否看着有点像集合？不错，集合就是泛型的一个典型运用

    //2.在方法上声明（定义,方法上，类型变量声明（定义）不是在参数里边，而且必须在返回值之前,static等修饰后
    public <E> void test(E e) {
    }


    class B {
        //3.声明（定义）在构造器上
        public <K> B(K k) {
        }
    }

//    ============================[ extends 和 super的区别 ]===========================

//    关键字说明
//    ? 通配符类型
//    <? extends T> 表示类型的上界，表示参数化类型的可能是T 或是 T的子类
//    <? super T> 表示类型下界（Java Core中叫超类型限定），表示参数化类型是此类型的超类型（父类型），直至Object

//    看了这个我是不太明白，换成白话是这个意思：

//    List<? extends T> 是说 这个list放的是T或者T的子类型的对象，但是不能确定具体是什么类型，所以可以get（），不能add（）（可以add null值）
//
//    List<? super T> 是说这个list放的是至少是T类型的对象，所以我可以add T或者T的子类型，但是get得到的类型不确定，所以不能获取

//    ================================================================================

    static class Food {
        public void eat() {
            System.out.println("food");
        }
    }

    static class Apple extends Food {
        public void eat() {
            System.out.println("apple");
        }
    }

    static class RedApple extends Apple {
        public void eat() {
            System.out.println("redApple");
        }
    }

    public static void main(String[] args) {
        // 造数
        List<Apple> apples = new ArrayList<>();
        apples.add(new Apple());
        apples.add(new Apple());
        apples.add(new Apple());

        ArrayList<Food> foods = new ArrayList<>();
        ArrayList<RedApple> redApples = new ArrayList<>();


        // 任何Food的子类的列表都能赋值成功，也可以取值，但是不能添加除null以外的元素
        List<? extends Food> foodList = apples;
//        foodList.add(new Food()); // error
//        foodList.add(new Apple()); // error
//        foodList.add(new Food());  // error
        foodList.add(null);
        test(foods);


        //  因为super表示下届，所以foods和apples都可以赋值成功，但是Apple的子类不行。
        List<? super Apple> list1 = foods;
        List<? super Apple> list = apples;
//        List<? super Apple> list2 = redApples;  // error


        // 可以添加Apple及其子类，但是不是添加任何Apple的父类
//        list.add(new Food()); // error
        list.add(new Apple());
        list.add(new RedApple());
        Object object = list.get(0);

    }

    public static <T extends Food> void test(List<T> foods) {
        for (T f : foods) {
            f.eat();
        }
    }
}
